﻿using DotPowerJob.Models;
using DotPowerJob.Requests;
using Flurl;
using Flurl.Http;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Linq;
using CZGL.SystemInfo;

namespace DotPowerJob.Hosted
{
    /// <summary>
    /// 心跳检测
    /// </summary>
    public class JobWorkerHeartbeat : BackgroundService
    {
        private readonly ILogger _logger;
        private PowerJobConfig _config;
        private static CPUTime oldCpuTime;
        public JobWorkerHeartbeat(
            ILogger<JobWorkerHeartbeat> logger,
            IOptions<PowerJobConfig> options)
        {
            _logger = logger;
            if (options == null)
                throw new ArgumentNullException(nameof(options));
            _config = options.Value;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                try
                {
                    if (string.IsNullOrWhiteSpace(PowerJobCache.ServerAddress))
                    {
                        await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
                        continue;
                    }
                    var request = new WorkerHeartbeatRequest()
                    {
                        AppId = PowerJobCache.AppId,
                        AppName = this._config.AppName,
                        WorkerAddress = this._config.ClientAddress,
                        HeartbeatTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                        Protocol = this._config.Protocol,
                        SystemMetrics = this.GetSystemInfo()
                    };
                    var requestJsonStr = JsonConvert.SerializeObject(request, new JsonSerializerSettings()
                    {
                        ContractResolver = new CamelCasePropertyNamesContractResolver()
                    });
                    var httpcontext = new StringContent(requestJsonStr);
                    var json = await PowerJobCache.ServerAddress.AppendPathSegment("/server/workerHeartbeat")
                        .WithHeader("content-Type", "application/json")
                        .PostAsync(httpcontext, System.Net.Http.HttpCompletionOption.ResponseContentRead)
                        .ReceiveString();
                    await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
                }
                catch (TaskCanceledException)
                {
                    this._logger.LogInformation("--- Application Stopping ---");
                }
                catch (Exception ex)
                {
                    await Task.Delay(TimeSpan.FromSeconds(15), stoppingToken);
                    this._logger.LogError(ex, "DiscoveryService error:{0}", ex.Message);
                }
            }
        }

        private SystemMetrics GetSystemInfo()
        {
            //处理器数量
            var cpuProcessors = SystemPlatformInfo.ProcessorCount;

            var newCpuTime = CPUHelper.GetCPUTime();

            var cpuLoad = CPUHelper.CalculateCPULoad(oldCpuTime, newCpuTime) * cpuProcessors;

            oldCpuTime = newCpuTime;

            //字节转换GB
            var unitConvert = 1024.00 * 1024.00 * 1024.00;

            var diskInfo = DiskInfo.GetDisks();
            //磁盘总容量
            var diskTotalSize = diskInfo.Sum(q => q.TotalSize) / unitConvert;
            //磁盘已使用容量
            var diskUsedSize = diskInfo.Sum(q => q.UsedSize) / unitConvert;

            var memory = MemoryHelper.GetMemoryValue();
            //总物理内存
            var totalMemoty = memory.TotalPhysicalMemory / unitConvert;
            //已使用物理内存
            var usedMemoty = memory.UsedPhysicalMemory / unitConvert;

            var systemNetrics = new SystemMetrics()
            {
                CpuLoad = (decimal)cpuLoad,
                CpuProcessors = cpuProcessors,
                DiskTotal = (decimal)diskTotalSize,
                DiskUsed = (decimal)diskUsedSize,
                DiskUsage = (decimal)(diskUsedSize / diskTotalSize),
                JvmMaxMemory = (decimal)totalMemoty,
                JvmUsedMemory = (decimal)usedMemoty,
                JvmMemoryUsage = (decimal)(usedMemoty / totalMemoty),
                Score = 0
            };
            return systemNetrics;
        }
    }
}
